﻿using System;
using FireStarter.Base;
using Firestarter.DB.Schema.BO;
using Firestarter.DB.Schema.UI;
using Habanero.Base;
using Habanero.Base.Exceptions;
using Habanero.BO;
using NUnit.Framework;

namespace Firestarter.DB.Schema.Test.UI
{
    [TestFixture]
    public class TestMergeBOsControl : TestBase
    {
        // ReSharper disable InconsistentNaming
        [Test]
        public void Test_Construct()
        {
            //---------------Set up test pack-------------------
            
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            var control = new MergeBOsControl();
            //---------------Test Result -----------------------
           
            Assert.IsNotNull(control);
            Assert.IsNull(control.BoSelectedInTree);
            Assert.IsNull(control.MergeableBoCombo.BusinessObjectCollection);
        }

        [Test]
        public void Test_SelectedTable_WhenSetToDBTableWithPendingChangeTypeAdd_ShouldSetMergeTablesLabelText()
        {
            //---------------Set up test pack-------------------
            const string mergeTableWith = "Merge with :";
            var control = CreateMergeTablesControl();
            var table = CreateAddedTable();
            //---------------Assert Precondition----------------
            //Assert.AreEqual(mergeTableWith, control.MergeBOsLabel.Text);
            //---------------Execute Test ----------------------
            control.BoSelectedInTree = table;
            //---------------Test Result -----------------------
            Assert.AreEqual(mergeTableWith, control.MergeBOsLabel.Text);
        }

        [Test]
        public void Test_SelectedTable_WhenSetToDBTableWithPendingChangeTypeDelete_ShouldSetMergeTablesLabelText()
        {
            //---------------Set up test pack-------------------
            const string mergeTableWith = "Merge with :";
            const string mergeTableInto = "Merge into :";
            var control = CreateMergeTablesControl();
            var table = CreateDeletedTable();
            //---------------Assert Precondition----------------
            Assert.AreEqual(mergeTableWith, control.MergeBOsLabel.Text);
            //---------------Execute Test ----------------------
            control.BoSelectedInTree = table;
            //---------------Test Result -----------------------
            Assert.AreEqual(mergeTableInto, control.MergeBOsLabel.Text);
        }

        #region GetToBeDeletedTable

        [Test]
        public void Test_GetToBeDeletedTable_WhenSelectedTablePendingChangeType_Delete_ShouldReturnSelectedTable()
        {

            //---------------Set up test pack-------------------
            MergeBOsControl control = CreateMergeTablesControl();
            var table = CreateDeletedTable();
            control.BoSelectedInTree = table;

            //---------------Assert Precondition----------------
            Assert.AreSame(table, control.BoSelectedInTree);
            Assert.AreEqual(ChangeType.Delete, table.PendingChangeType);
            //---------------Execute Test ----------------------
            IMergableBo mergeToTable = control.GetToBeDeletedMergableBo();
            //---------------Test Result -----------------------
            Assert.AreSame(table, mergeToTable);
        }

        [Test]
        public void Test_GetToBeDeletedTable_WhenSelectedTablePendingChangeType_NotAddOrDelete_ShouldThrowHabaneroDeveloperException()
        {
            //---------------Set up test pack-------------------
            MergeBOsControl control = CreateMergeTablesControl();
            var table = GetNoneTable();
            control.BoSelectedInTree = table;
            SetTableSelectedInComboBox(control);
            //---------------Assert Precondition----------------
            Assert.AreSame(table, control.BoSelectedInTree);
            Assert.AreEqual(ChangeType.None, table.PendingChangeType);
            //---------------Execute Test ----------------------
            try
            {
                control.GetToBeDeletedMergableBo();
                Assert.Fail("Test should raise an Exception");
            }
            catch (Exception ex)
            {
                //---------------Test Result -----------------------
                Assert.IsInstanceOf<HabaneroDeveloperException>(ex);
                StringAssert.Contains("PendingChangeType", ex.Message);
                StringAssert.Contains("should be Add or Delete", ex.Message);
            }
        }

        [Test]
        public void Test_GetToBeDeletedTable_WhenSelectedTablePendingChangeType_Add_AndNoRenamedTableSelected_ShouldThrowHabaneroDeveloperException()
        {
            //---------------Set up test pack-------------------
            var control = CreateMergeTablesControl();
            var table =  CreateAddedTable();
            control.BoSelectedInTree = table;

            //---------------Assert Precondition----------------
            Assert.AreSame(table, control.BoSelectedInTree);
            Assert.AreEqual(ChangeType.Add, table.PendingChangeType);
            //---------------Execute Test ----------------------
            try
            {
                control.GetToBeDeletedMergableBo();
                Assert.Fail("Test should raise an Exception");
            }
            catch (Exception ex)
            {
                //---------------Test Result -----------------------
                Assert.IsInstanceOf<HabaneroDeveloperException>(ex);
                StringAssert.Contains("was selected from the Dropdown list.", ex.Message);
            }
        }

        [Test]
        public void Test_GetToBeDeletedTable_WhenSelectedTablePendingChangeType_Add_ShouldReturnTableFromMergeTablesCombo()
        {
            //---------------Set up test pack-------------------
            MergeBOsControl control = CreateMergeTablesControl();
            control.BoSelectedInTree = CreateAddedTable();
            control.MergeableBoCombo.BusinessObjectCollection = CreateBOCol(ChangeType.Delete);
            //---------------Assert Precondition----------------
            IBusinessObjectCollection boCol = control.MergeableBoCombo.BusinessObjectCollection;
            Assert.AreEqual(1, boCol.Count);
            var deletedTable = (IMergableBo)boCol[0];
            Assert.AreEqual(ChangeType.Delete, deletedTable.PendingChangeType);
            //---------------Execute Test ----------------------
            IMergableBo mergeToTable = control.GetToBeDeletedMergableBo();
            //---------------Test Result -----------------------
            Assert.AreSame(deletedTable, mergeToTable);
        }

        #endregion

        #region GetToBeAddedTable

        [Test]
        public void Test_GetToBeAddedTable_WhenSelectedTablePendingChangeType_NotAddOrDelete_ShouldThrowHabaneroDeveloperException()
        {
            //---------------Set up test pack-------------------
            MergeBOsControl control = CreateMergeTablesControl();
            var table = GetNoneTable();
            control.BoSelectedInTree = table;
            SetTableSelectedInComboBox(control);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(control.BoSelectedInComboBox);
            Assert.AreSame(table, control.BoSelectedInTree);
            Assert.AreEqual(ChangeType.None, table.PendingChangeType);
            //---------------Execute Test ----------------------
            try
            {
                control.GetToBeAddedMergableBo();
                Assert.Fail("Test should raise an Exception");
            }
            catch (Exception ex)
            {

                //---------------Test Result -----------------------
                Assert.IsInstanceOf<HabaneroDeveloperException>(ex);
                StringAssert.Contains("PendingChangeType", ex.Message);
                StringAssert.Contains("should be Add or Delete", ex.Message);
            }
        }

        [Test]
        public void Test_GetToBeAddedTable_WhenSelectedTablePendingChangeType_Delete_AndNoRenamedTableSelected_ShouldThrowHabaneroDeveloperException()
        {
            //---------------Set up test pack-------------------
            MergeBOsControl control = CreateMergeTablesControl();
            var table = CreateDeletedTable();
            control.BoSelectedInTree = table;

            //---------------Assert Precondition----------------
            Assert.AreSame(table, control.BoSelectedInTree);
            Assert.AreEqual(ChangeType.Delete, table.PendingChangeType);
            //---------------Execute Test ----------------------
            try
            {
                control.GetToBeAddedMergableBo();
                Assert.Fail("Test should raise an Exception");
            }
            catch (Exception ex)
            {

                //---------------Test Result -----------------------
                Assert.IsInstanceOf<HabaneroDeveloperException>(ex);
                StringAssert.Contains("was selected from the Dropdown list.", ex.Message);
            }
        }

        [Test]
        public void Test_GetToBeAddedTable_WhenSelectedTablePendingChangeType_Add_ShouldReturnSelectedTable()
        {
            //---------------Set up test pack-------------------
            var control = CreateMergeTablesControl();
            var table = CreateAddedTable();
            control.BoSelectedInTree = table;

            //---------------Assert Precondition----------------
            Assert.AreSame(table, control.BoSelectedInTree);
            Assert.AreEqual(ChangeType.Add, table.PendingChangeType);
            //---------------Execute Test ----------------------
            var mergeToTable = control.GetToBeAddedMergableBo();
            //---------------Test Result -----------------------
            Assert.AreSame(table, mergeToTable);
        }

        [Test]
        public void Test_GetToBeAddedTable_WhenSelectedTablePendingChangeType_Delete_ShouldReturnSelectedTableFromRenamedTablesCombo()
        {
            //---------------Set up test pack-------------------
            var control = CreateMergeTablesControl();
            control.BoSelectedInTree = CreateDeletedTable();
            control.MergeableBoCombo.BusinessObjectCollection = CreateBOCol(ChangeType.Add);
            //---------------Assert Precondition----------------
            var boCol = control.MergeableBoCombo.BusinessObjectCollection;
            Assert.AreEqual(1, boCol.Count);
            var addedTable = boCol[0] as IMergableBo;
            Assert.IsNotNull(addedTable);
            Assert.AreEqual(ChangeType.Add, addedTable.PendingChangeType);
            //---------------Execute Test ----------------------
            var mergeToTable = control.GetToBeAddedMergableBo();
            //---------------Test Result -----------------------
            Assert.AreSame(addedTable, mergeToTable);
        }

        #endregion

/*        [Test]
        public void Test_CanMergeTable()
        {
            //---------------Set up test pack-------------------
            SchemaMerger.SetupMergeableBORegistry();
            var mergeBO = MergeableBORegistry.Instance.Resolve<DBTable>();
            var fromTable = new DBTable("fromTable");
            fromTable.Columns.Add(new DBColumn("col1"));
            fromTable.Columns.Add(new DBColumn("col2"));
            var toTable = new DBTable("toTable");
            toTable.Columns.Add(new DBColumn("col2"));
            toTable.Columns.Add(new DBColumn("col3"));

            //---------------Assert Precondition----------------
            Assert.AreEqual(2, fromTable.Columns.Count);
            Assert.AreEqual(2, toTable.Columns.Count);
            //---------------Execute Test ----------------------
            var mergedTable = mergeBO.MergeBOFrom(fromTable, toTable);

            //---------------Test Result -----------------------
            Assert.AreEqual(2, fromTable.Columns.Count);
            Assert.AreEqual(3, toTable.Columns.Count);
            Assert.AreEqual(3, mergedTable.Columns.Count); 
            Assert.AreEqual("fromTable", mergedTable.TableName);
            Assert.AreSame(toTable, mergedTable);

        }*/
/*
        [Test]
        public void Test_CanRemoveTablesFromDatabase()
        {
            //---------------Set up test pack-------------------
            var database = new DBDatabase {DatabaseName = "myDB"};
            var table1 = new DBTable("table1");
            var tableBuilder = new DBTableBuilder(table1);
            tableBuilder.AddColumn("col1");
            tableBuilder.AddColumn("col2");

            DBTable table2 = new DBTable("table2");
            tableBuilder = new DBTableBuilder(table2);
            tableBuilder.AddColumn("col1");
            tableBuilder.AddColumn("col2");

            database.Tables.Add(table1);
            database.Tables.Add(table2);


            //---------------Assert Precondition----------------

            Assert.AreEqual(2,database.Tables.Count);

            //---------------Execute Test ----------------------
            database.Tables.Find(x => x.TableName=="table2").MarkForDelete();
            database.Save();
            //database.Tables.Remove(table2);
            //---------------Test Result -----------------------
            Assert.AreEqual(1,database.Tables.Count);
            Assert.AreSame(table1,database.Tables[0]);

        }*/


        private void SetTableSelectedInComboBox(MergeBOsControl control)
        {
            control.MergeableBoCombo.BusinessObjectCollection = CreateBOCol(ChangeType.None);
        }

        protected virtual IMergableBo GetNoneTable()
        {
            return new DBTable("selectedTable") { PendingChangeType = ChangeType.None };
        }

        protected virtual IMergableBo CreateAddedTable()
        {
            return new DBTable("addedTable") { PendingChangeType = ChangeType.Add };
        }

        protected virtual IMergableBo CreateDeletedTable()
        {
            return new DBTable("deletedTable") { PendingChangeType = ChangeType.Delete };
        }

        protected virtual MergeBOsControl CreateMergeTablesControl()
        {
            return new MergeBOsControl();
        }

        protected virtual IBusinessObjectCollection CreateBOCol(ChangeType changeType)
        {
            IMergableBo businessObjects = CreateTable(changeType);
            IBusinessObjectCollection businessObjectCollection = CreateBusinessObjectCollection();
            businessObjectCollection.Add(businessObjects);
            return businessObjectCollection;
        }

        protected virtual IBusinessObjectCollection CreateBusinessObjectCollection()
        {
            return new BusinessObjectCollection<DBTable>();
        }

        protected virtual IMergableBo CreateTable(ChangeType changeType)
        {
            return new DBTable("SomeTable") {PendingChangeType = changeType};
        }
    }

    public class TestMergeBOsControlForColumns : TestMergeBOsControl
    {
        protected override IMergableBo GetNoneTable()
        {
            return new DBColumn("selectedTable") { PendingChangeType = ChangeType.None };
        }

        protected override IMergableBo CreateAddedTable()
        {
            return new DBColumn("addedTable") { PendingChangeType = ChangeType.Add };
        }

        protected override IMergableBo CreateDeletedTable()
        {
            return new DBColumn("deletedTable") { PendingChangeType = ChangeType.Delete };
        }

        protected override IBusinessObjectCollection CreateBusinessObjectCollection()
        {
            return new BusinessObjectCollection<DBColumn>();
        }

        protected override IMergableBo CreateTable(ChangeType changeType)
        {
            return new DBColumn("SomeTable") { PendingChangeType = changeType };
        }
    }
    // ReSharper restore InconsistentNaming
}